using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;

public class CustomShaderGUI : ShaderGUI
{
    MaterialEditor editor;
    Object[] materials;
    MaterialProperty[] properties;
    bool showButtons = true;

    enum ShadowMode
    {
        On, Clipped,Dithered,Off
    }


    public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
    {
        EditorGUI.BeginChangeCheck();
        base.OnGUI(materialEditor, properties);
        this.editor = materialEditor;
        this.materials = materialEditor.targets;
        this.properties = properties;

        BakedEmission();

        EditorGUILayout.Space();

        showButtons = EditorGUILayout.Foldout(showButtons, "QuickButtons", true);
        if(showButtons)
        {
            ShowButtonOpaque();
            ShowButtonClips();
            ShowButtonFade();
            ShowButtonTransparent();
        }
        if(EditorGUI.EndChangeCheck())
        {
            SetShadowCasterPass();
            CopyLightMappingProperties();
        }
      
    }

    void BakedEmission()
    {
        EditorGUI.BeginChangeCheck();
        editor.LightmapEmissionProperty();
        if(EditorGUI.EndChangeCheck())
        {
            foreach(Material m in editor.targets)
            {
                m.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
            }
        }
    }

    void CopyLightMappingProperties()
    {
        MaterialProperty mainTex = FindProperty("_MainTex", properties, false);
        MaterialProperty baseMap = FindProperty("_BaseMap", properties, false);
        if(mainTex !=null && baseMap != null)
        {
            mainTex.textureValue = baseMap.textureValue;
            mainTex.textureScaleAndOffset = baseMap.textureScaleAndOffset;
        }

        MaterialProperty color = FindProperty("_Color", properties, false);
        MaterialProperty baseColor = FindProperty("_BaseColor", properties, false);
        if(color != null && baseColor != null)
        {
            color.colorValue = baseColor.colorValue;
        }
    }

    bool ShowButton(string name)
    {
        
        if (GUILayout.Button(name))
        {
            editor.RegisterPropertyChangeUndo(name);
            return true;
        }
        return false;
    }
    void ShowButtonOpaque()
    {
        if(ShowButton("Opaque"))
        {
            Clipping = false;
            PremultiplyAlpha = false;
            SrcBlend = BlendMode.One;
            DstBlend = BlendMode.Zero;
            ZWrite = true;
            RenderQueue = RenderQueue.Geometry;
        }
    }
    void ShowButtonClips()
    {
        if (ShowButton("Clips"))
        {
            Clipping = true;
            PremultiplyAlpha = false;
            SrcBlend = BlendMode.One;
            DstBlend = BlendMode.Zero;
            ZWrite = true;
            RenderQueue = RenderQueue.AlphaTest;
        }
    }
    void ShowButtonFade()
    {
        if (ShowButton("Fade"))
        {
            Clipping = false;
            PremultiplyAlpha = false;
            SrcBlend = BlendMode.SrcAlpha;
            DstBlend = BlendMode.OneMinusSrcAlpha;
            ZWrite = false;
            RenderQueue = RenderQueue.Transparent;
        }
    }
    void ShowButtonTransparent()
    {
        if (!HasPremultiplyAlpha) return ;

        if (ShowButton("Transparent"))
        {
            Clipping = false;
            PremultiplyAlpha = true;
            SrcBlend = BlendMode.One;
            DstBlend = BlendMode.OneMinusSrcAlpha;
            ZWrite = false;
            RenderQueue = RenderQueue.Transparent;
        }
    }

    bool HasProperty(string name) => FindProperty(name, properties, false) != null;
    bool SetProperty(string name,float value)
    {
        if(HasProperty(name))
        {
            FindProperty(name, this.properties).floatValue = value;
            return true;
        }
            
        return false;
    }

    void setKeywordEnabled(string keyword,bool enable)
    {
        if(enable)
        {
            foreach(Material m in this.materials)
            {
                m.EnableKeyword(keyword);
            }
        }
        else
        {
            foreach (Material m in this.materials)
            {
                m.DisableKeyword(keyword);
            }
        }
    }

    void SetPropertyEnabled(string name,string keyword,bool enable)
    {
        setKeywordEnabled(keyword, enable);
        SetProperty(name, enable ? 1f:0f);
       
    }

    void SetShadowCasterPass()
    {
        MaterialProperty shadows = FindProperty("_Shadows", this.properties, false);
        if(shadows == null || shadows.hasMixedValue)
        {
            return;
        }
        bool enabled = shadows.floatValue < (float)ShadowMode.Off;
        foreach(Material m in this.materials)
        {
            m.SetShaderPassEnabled("ShadowCaster", enabled);
        }
    }

    bool Clipping
    {
        set => SetPropertyEnabled("_Clipping", "_CLIPPING", value);
    }
     
    bool PremultiplyAlpha
    {
        set => SetPropertyEnabled("_PremultiplyAlpha", "_DIFFUSE_PREMULTIPLY_ALPHA", value);
    }
    bool HasPremultiplyAlpha
    {
        get => HasProperty("_PremultiplyAlpha");
    }

    BlendMode SrcBlend
    {
        set => SetProperty("_SrcBlend", (float)value);
    }

    BlendMode DstBlend
    {
        set => SetProperty("_DstBlend", (float)value);
    }

    bool ZWrite
    {
        set => SetProperty("_ZWrite", value ? 1f : 0f);
    }

    RenderQueue RenderQueue
    {
        set
        {
            foreach(Material m in materials)
            {
                m.renderQueue = (int)value;
            }
        }
    }

    ShadowMode Shadows
    {
        set
        {
            if(SetProperty("_Shadows",(float) value))
            {
                setKeywordEnabled("_SHADOWS_CLIP", value == ShadowMode.Clipped);
                setKeywordEnabled("_SHADOWS_DITHER", value == ShadowMode.Dithered);
            }
        }
    }
}
